//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Security;
using System.Linq;

namespace DNA.Mvc.Controllers
{
    /// <summary>
    /// The controller manages user membership in roles for authorization checking in an ASP.NET application. 
    /// </summary>
    //[HandleError]
    public class SecurityController : Controller
    {
        private WebSiteContext _context;
        public SecurityController(WebSiteContext context) { _context = context; }
        
        public ActionResult Index()
        {
            return View("_RoleForm");
        }

        /// <summary>
        /// Get the role list view of the Portal
        /// </summary>
        /// <returns></returns>
        [SiteControlPanel(ResKey = "RES_MEMBERSHIP", Group = "Security", GroupResKey = "RES_SECURITY", Sequence = 2, ShowInTopSiteOnly = true)]
        [SecurityAction("Manage users", 
            PermssionSet = "Security", 
            Description = "Allows user to access the security control panel",
            TitleResName = "SA_ManageUsers",
            DescResName = "SA_ManageUsersDesc",
            PermssionSetResName = "SA_SECURITY"
            )]
        public ActionResult ManageUsers()
        {
            return View();
        }

        [SiteControlPanel(ResKey = "RES_ROLES", Group = "Security", GroupResKey = "RES_SECURITY", Sequence = 1, ShowInTopSiteOnly = true)]
        [SecurityAction("Manage Roles", 
            PermssionSet="Security",
            Description="Allows users to manage the roles of the web.",
            TitleResName = "SA_ManageRoles",
            DescResName = "SA_ManageRolesDesc",
            PermssionSetResName = "SA_SECURITY"
            )]
        public ActionResult ManageRoles()
        {
            ViewData.Model = Roles.GetAllRoles();
            return PartialView();
        }

        /// <summary>
        /// Adds a new role to the data source.
        /// </summary>
        /// <param name="NewRoleName">The name of the role to create.</param>
        /// <returns>if create role successful</returns>
        [HttpPost]
        [SecurityAction("Create roles",
            PermssionSet = "Security",
            Description = "Allows user could create the roles for the website.",
            TitleResName = "SA_CreateRoles",
            DescResName = "SA_CreateRolesDesc",
            PermssionSetResName = "SA_SECURITY"
            )]
        [ValidateAntiForgeryToken]
        public ActionResult Create(string NewRoleName)
        {
            if (!string.IsNullOrEmpty(NewRoleName))
                try
                {
                    Roles.CreateRole(NewRoleName);
                }
                catch (Exception e)
                {
                    ModelState.AddModelError("NewRoleName", e);
                    return RedirectToAction("ManageRoles");
                }
            else
                ModelState.AddModelError("NewRoleName", Resources.language.RoleNameIsRequried);
            return RedirectToAction("ManageRoles");
        }

        /// <summary>
        /// Removes a role from the data source.
        /// </summary>
        /// <param name="roleName">The name of the role to delete.</param>
        /// <returns>The ActionResult.</returns>
        [HttpPost]
        [SecurityAction("Delete roles", 
            PermssionSet = "Security",
            Description = "Allows user to delete the roles for the website.",
            TitleResName = "SA_DeleteRoles",
            DescResName = "SA_DeleteRolesDesc",
            PermssionSetResName = "SA_SECURITY"
            )]
        public ActionResult Delete(string roleName)
        {
            Roles.DeleteRole(Server.UrlDecode(roleName));
            return RedirectToAction("ManageRoles");
        }

        /// <summary>
        /// Adds the specified user to the specified role.
        /// </summary>
        /// <param name="user"> The user name to add to the specified role.</param>
        /// <param name="roleName"> The role to add the specified user name to.</param>
        /// <returns>If successful return true.</returns>
        [HttpPost]
        [SecurityAction("Add roles to user", 
            PermssionSet = "Security",
            Description = "Allows to add the exists roles to the users.",
            TitleResName = "SA_AddRolesToUser",
            DescResName = "SA_AddRolesToUserDesc",
            PermssionSetResName = "SA_SECURITY"
            )]
        public bool AddUser(string user, string roleName)
        {
            Roles.AddUserToRole(user, roleName);
            return true;
        }

        /// <summary>
        /// Removes the specified user from the specified role.
        /// </summary>
        /// <param name="user">The user to remove from the specified role.</param>
        /// <param name="roleName">The role to remove the specified user from.</param>
        /// <returns>If successful return true.</returns>
        [AcceptVerbs(HttpVerbs.Post)]
        [SecurityAction("Remove roles from user", 
            PermssionSet = "Security",
            Description = "Allows to remove the roles from the exists users.",
            TitleResName = "SA_RemoveRolesFromUser",
            DescResName = "SA_RemoveRolesFromUserDesc",
            PermssionSetResName = "SA_SECURITY"
            )]
        public bool RemoveUser(string user, string roleName)
        {
            Roles.RemoveUserFromRole(user, roleName);
            return true;
        }

        /// <summary>
        /// Get the permissions view for the specified role
        /// </summary>
        /// <param name="role">the name of the role to list</param>
        /// <returns></returns>
        [Authorize]
        public ActionResult RoleDetail(string role)
        {
            ViewData.Model = _context.DataContext.PermissionSets.All().OrderBy(p=>p.Name);
            ViewData["Role"] = role;
            return PartialView();
        }

        [HttpPost]
        [SecurityAction("Security", "Manage the permissions", "Allows users to manage the permissions of the role.",
            TitleResName = "SA_ManagePermissions",
            DescResName = "SA_ManagePermissions_Desc",
            PermssionSetResName = "SA_SECURITY"
            )]
        [ValidateAntiForgeryToken]
        public ActionResult Apply(string roleName, FormCollection forms)
        {
            List<int> keys = new List<int>();
            foreach (string key in forms.Keys)
            {
                var selected = false;
                bool.TryParse(forms[key], out selected);
                if (!selected) continue;

                if (key.StartsWith("perm_"))
                {
                    int k = int.MinValue;
                    if (int.TryParse(key.Substring(5), out k))
                        keys.Add(k);
                }
            }
            
            var perms=_context.DataContext.Permissions.GetPermissions(keys.ToArray());
            
            _context.DataContext.Permissions.ClearFromRole(roleName);
            _context.DataContext.Permissions.AddPermissionsToRole(perms, roleName);
            _context.DataContext.SaveChanges();

            return RedirectToAction("ManageRoles");
        }

        [Authorize]
        public ActionResult UserDetail(string id)
        {
            if (_context.IsAuthorized(this,"ManageUsers"))
            {
                return PartialView(Membership.GetUser(id));
            }
            else
                return Content(Resources.language.AccessDenied_MSG);
        }
        
        [Authorize]
        public void UpdateUserRoles(string username, string roles)
        {
            if (_context.IsAuthorized(this, "ManageUsers"))
            {
                if (string.IsNullOrEmpty(username))
                    throw new ArgumentNullException("username");

                if (string.IsNullOrEmpty(roles))
                    throw new ArgumentNullException("roles");

                var userRoles = Roles.GetRolesForUser(username);
                Roles.RemoveUserFromRoles(username, userRoles);
                Roles.AddUserToRoles(username, roles.Split(','));
            }
        }

        [Authorize]
        public void Bend(string username)
        {
            if (_context.IsAuthorized(this, "ManageUsers"))
            {
                var user = Membership.GetUser(username);
                user.IsApproved = false;
                Membership.UpdateUser(user);
            }
        }

        [Authorize]
        public void Unlock(string username)
        {
            if (_context.IsAuthorized(this, "ManageUsers"))
            {
                var user = Membership.GetUser(username);
                user.IsApproved = true;
                Membership.UpdateUser(user);
                user.UnlockUser();
            }
        }
    }
}
